import json
from collections import OrderedDict

from django.utils.translation import gettext_lazy, gettext as _
from rest_framework.decorators import action
from rest_framework.response import Response
from drf_yasg.utils import swagger_auto_schema, no_body
from drf_yasg import openapi
from rest_framework.serializers import Serializer

from api.harbor import HarborManager
from utils.view import CustomGenericViewSet
from api import permissions, serializers, paginations
from api import exceptions
from rest_framework import status
from api.views_v1.views import check_authenticated_or_bucket_token, serializer_error_text


class ObjUserTagsViewSet(CustomGenericViewSet):
    """
    用户标签
    """
    permission_classes = [permissions.IsAuthenticatedOrBucketToken]
    lookup_field = 'objpath'
    lookup_value_regex = '.+'

    @swagger_auto_schema(
        operation_summary=gettext_lazy('检索标签对象'),
        manual_parameters=[
            openapi.Parameter(
                name='tag_key', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("标签键"),
                required=True
            ),
            openapi.Parameter(
                name='tag_value', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("标签值"),
                required=False,
            ),
        ],
        responses={
            200: ""
        }
    )
    def list(self, request, *args, **kwargs):
        """
        检索桶内标签对象

            >>Http Code: 状态码200：
            {
              "bucket": "testcopy",
              "files": [
                {
                  "na": "abc.py",
                  "name": "abc.py",
                  "fod": true,
                  "did": 0,
                  "si": 35,
                  "ult": "2020-12-18T18:02:45.715877+08:00",
                  "upt": "2021-03-01T16:56:10.524571+08:00",
                  "dlc": 0,
                  "download_url": "http://xxx/share/obs/testcopy/abc.py",
                  "access_permission": "私有",
                  "access_code": 0,
                  "md5": "585e699b26602e7dd6054798d8c22d9b"
                  "async1": null,
                  "async2": null
                }
              ],
              "count": 2,
              "next": null,
              "page": {
                "current": 1,
                "final": 1
              },
              "previous": null
            }

            >>Http Code 400, 401, 403, 404, 500:
            {
              "code": "xxx",    # 错误码， BadRequest、AccessDenied等
              "message": "xxx"  # 错误描述
            }
        """
        bucket_name = kwargs.get('bucket_name', '')
        tag_key = request.query_params.get('tag_key', '')
        tag_value = request.query_params.get('tag_value', '')

        if not bucket_name:
            exc = exceptions.BadRequest(message=_(f'存储桶不能为空。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        if not tag_key:
            exc = exceptions.BadRequest(message=_(f'标签键不能为空。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        if tag_value and not isinstance(tag_value, str):
            exc = exceptions.BadRequest(message=_(f'标签键必须为字符串。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='read', view=self)
        except exceptions.Error as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        h_manager = HarborManager()

        try:
            bucket, queryset = h_manager.search_tag_object_queryset(bucket=bucket_name, user=request.user,
                                                                    tag_key=tag_key, tag_value=tag_value)
        except exceptions.HarborError as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            paginator = paginations.BucketFileLimitOffsetPagination()
            files = paginator.paginate_queryset(queryset, request=request)
            serializer = serializers.ObjInfoSerializer(files, many=True, context={
                'bucket_name': bucket_name, 'bucket': bucket, 'request': request})
            files = serializer.data
        except Exception as exc:
            exc = exceptions.Error(message=str(exc))
            return Response(data=exc.err_data(), status=exc.status_code)

        data_dict = OrderedDict([
            ('bucket', bucket_name),
            ('files', files)
        ])
        return paginator.get_paginated_response(data_dict)

    @swagger_auto_schema(
        operation_summary=gettext_lazy('列举文件对象标签'),

        responses={
            200: """{
                        "bucket_name": "test-bucket-s3",
                        "obj_name": "bash_history",
                        "obj_path": "",
                        "tags": {
                          "lable": "2333",
                          "lable2": 2333
                        } 
                    }
                    """
        }
    )
    def list_detail(self, request, *args, **kwargs):
        """
        查看标签

            >>Http Code: 状态码200：
            {
                "bucket_name": "test-bucket-s3",
                "obj_name": "bash_history",
                "obj_path": "",
                "tags": {
                  "lable": "2333",
                  "lable2": 2333
                }
            }

            >>Http Code 400, 401, 403, 404, 500:
            {
              "code": "xxx",    # 错误码， BadRequest、AccessDenied等
              "message": "xxx"  # 错误描述
            }
        """
        objpath = kwargs.get(self.lookup_field, '')
        bucket_name = kwargs.get('bucket_name', '')

        if not bucket_name or not objpath:
            exc = exceptions.BadRequest(message=_(f'存储桶或文件路径不能为空。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='read', view=self)
        except exceptions.Error as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        hmanager = HarborManager()
        try:
            obj = hmanager.get_object(bucket_name=bucket_name, path_name=objpath, user=request.user)
        except exceptions.HarborError as e:
            return Response(data=e.err_data(), status=e.status_code)

        tags = obj.json_tags
        data = {'bucket_name': bucket_name, 'obj_name': obj.name, 'obj_path': obj.get_parent_path(),
                'tags': tags['tags'] if tags else {}
                }

        return Response(data, status=status.HTTP_200_OK)

    @swagger_auto_schema(
        operation_summary=gettext_lazy('添加/替换 用户标签'),
        responses={
            201: ""
        }
    )
    def update(self, request, *args, **kwargs):
        """
        添加/替换 标签, 标签限制：10个

        {"tags":{"tag_key": "tag_value"}}

            >>Http Code: 状态码201
            >>Http Code: 400 401 403 404 500
            {
              "code": "xxx",    # 错误码， BadRequest、AccessDenied等
              "message": "xxx"  # 错误描述
            }
        """
        objpath = kwargs.get(self.lookup_field, '')
        bucket_name = kwargs.get('bucket_name', '')

        if not bucket_name or not objpath:
            exc = exceptions.BadRequest(message=_(f'存储桶或文件路径不能为空。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        serializer = self.get_serializer(data=request.data)
        if not serializer.is_valid(raise_exception=False):
            msg = serializer_error_text(serializer.errors, default='标签数量超出最大值，默认为10个用户标签')
            return Response({'code': 'BadRequest', 'message': msg}, status=status.HTTP_400_BAD_REQUEST)

        data = serializer.validated_data

        if not data or not data['tags']:
            exc = exceptions.BadRequest(message=_('标签不能为空值。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='write', view=self)
        except exceptions.Error as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        hmanager = HarborManager()
        try:
            obj = hmanager.get_object(bucket_name=bucket_name, path_name=objpath, user=request.user)
        except exceptions.HarborError as e:
            return Response(data=e.err_data(), status=e.status_code)

        save_tag = obj.json_tags

        if not save_tag:
            save_tag = {}

        if 'tags' not in save_tag:
            save_tag['tags'] = {}

        data_length = len(data['tags'])
        tag_length = len(save_tag['tags']) + data_length

        if tag_length > 10:
            exc = exceptions.BadRequest(message=_('标签已超出最大值，默认为10个用户标签。'))
            # exc = exceptions.OutOfLimit(message=_('The maximum number of user labels has been reached. The default number is 10'))
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            save_tag['tags'].update(data['tags'])  # update 会覆盖原有的键
            obj.json_tags = save_tag
            obj.save(update_fields=['json_tags'])
        except Exception as e:
            exc = exceptions.Error(message=_(f'用户标签未添加成功，请重试， error : {str(e)}'))
            return Response(data=exc.err_data(), status=exc.status_code)

        return Response(status=status.HTTP_201_CREATED)

    @swagger_auto_schema(
        operation_summary=gettext_lazy('删除标签集'),
        request_body=no_body,
        responses={
            204: ""
        }
    )
    def destroy(self, request, *args, **kwargs):
        """
        删除用户标签：

            >>Http Code: 状态码204
            >>Http Code: 400 401 403 404 500
            {
              "code": "xxx",    # 错误码， BadRequest、AccessDenied等
              "message": "xxx"  # 错误描述
            }
        """

        objpath = kwargs.get(self.lookup_field, '')
        bucket_name = kwargs.get('bucket_name', '')

        if not bucket_name or not objpath:
            exc = exceptions.BadRequest(message=_(f'存储桶或文件路径不能为空。'))
            return Response(data=exc.err_data(), status=exc.status_code)

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='write', view=self)
        except exceptions.Error as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        hmanager = HarborManager()
        try:
            obj = hmanager.get_object(bucket_name=bucket_name, path_name=objpath, user=request.user)
        except exceptions.HarborError as e:
            return Response(data=e.err_data(), status=e.status_code)

        tag = obj.json_tags
        try:
            if 'tags' in tag:
                obj.json_tags['tags'].clear()
                obj.save(update_fields=['json_tags'])
        except Exception as e:
            exc = exceptions.Error(message=_(f'标签集未删除，请重试， error : {str(e)}'))
            return Response(data=exc.err_data(), status=exc.status_code)

        return Response(status=status.HTTP_204_NO_CONTENT)

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        if self.action == 'update':
            return serializers.UserTagsUpdateSerializer
        return Serializer
